﻿using System;
namespace PBRSystem.Coord
{
    public class PBRVector3
    {
        #region Variables
        private float _x, _y, _z;
        #endregion

        #region Contructor
        public PBRVector3()
        {
            _x = _y = _z = 0;
        }
        public PBRVector3(float x, float y, float z)
        {


            if(float.IsNaN(x) || float.IsNaN(y) || float.IsNaN(z))
            {
                x = y = z = 0;
            }

            _x = x;
            _y = y;
            _z = z;
        }
        public PBRVector3(PBRVector3 a)
        {
            if (float.IsNaN(a.X) || float.IsNaN(a.Y) || float.IsNaN(a.Z))
            {
                a.X = a.Y = a.Z = 0;
            }

            _x = a.X;
            _y = a.Y;
            _z = a.Z;
        }
        #endregion

        #region Operator Override

        public static PBRVector3 operator +(PBRVector3 a, PBRVector3 b)
        {
            return new PBRVector3(a.X + b.X, a.Y + b.Y, a.Z + b.Z);
        }

        public static PBRVector3 operator -(PBRVector3 a, PBRVector3 b)
        {
            return new PBRVector3(a.X - b.X, a.Y - b.Y, a.Z - b.Z);
        }

        public static PBRVector3 operator -(PBRVector3 a)
        {
            return new PBRVector3(-a.X,-a.Y, -a.Z);
        }

        public static PBRVector3 operator *(PBRVector3 a, PBRVector3 b)
        {
            return new PBRVector3(a.X * b.X, a.Y * b.Y, a.Z * b.Z);
        }

        public static PBRVector3 operator *(PBRVector3 a, float s)
        {
            return new PBRVector3(a.X * s, a.Y * s, a.Z * s);
        }

        public static PBRVector3 operator /(PBRVector3 a, PBRVector3 b)
        {
            if(b.X == 0 || b.Y == 0)
            {
                return a;
            }
            return new PBRVector3(a.X / b.X, a.Y / b.Y, a.Z / b.Z);
        }

        public static PBRVector3 operator /(PBRVector3 a, float s)
        {
            if(s == 0)
            {
                return a;
            }
            return new PBRVector3(a.X / s, a.Y / s, a.Z / s);
        }
        public static bool operator ==(PBRVector3 a, PBRVector3 b)
        {
            return (a.X == b.X) && (b.Y == b.Y) && (a.Z == b.Z);
        }
        public static bool operator !=(PBRVector3 a, PBRVector3 b)
        {
            return (a.X != b.X) && (a.Y != b.Y) && (b.Z != a.Z);
        }

        #endregion

        #region Reporter 

        public float X { get => _x; set => _x = value; }
        public float Y { get => _y; set => _y = value; }
        public float Z { get => _z; set => _z = value; }
        

        public override bool Equals(object obj)
        {
            if(!(obj is PBRVector3))
            {
                return false;
            }

            PBRVector3 b = (PBRVector3)obj;

            return (_x == b.X && _y == b.Y);
        }

        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

        public bool HasNaNs()
        {
            return float.IsNaN(_x) || float.IsNaN(_y) || float.IsNaN(_z);
        }


        public float MaxDimension(PBRVector3 a)
        {
            return Math.Max(a.X, Math.Max(a.Y,a.Z));
        }

        public float MinDimension(PBRVector3 a)
        {
            return Math.Min(a.X,Math.Min(a.Y, a.Z));
        }

        public PBRVector3 CoordSystem(PBRVector3 a, PBRVector3 b)
        {
            return null;
        }

        public float LengthSquard()
        {
            return _x * _x + _y * _y + _z * _z;
        }
        public float Length()
        {
            return (int)Math.Sqrt(LengthSquard());
        }


        #endregion

        #region Operation
        public PBRVector3 Cross(PBRVector3 a, PBRVector3 b)
        {
            float v1x = a.X;
            float v1y = a.Y;
            float v1z = a.Z;

            float v2x = b.X;
            float v2y = b.Y;
            float v2z = b.Z;

            return new PBRVector3((v1y * v2z) - (v1z * v2y),
                              (v1z * v2x) - (v1x * v2z),
                              (v1x * v2y) - (v1y * v2x));
        }
        public float Dot(PBRVector3 a, PBRVector3 b)
        {
            return a.X * b.X + a.Y + b.Y + a.Z * b.Z;
        }
        public float AbsDot(PBRVector3 a, PBRVector3 b)
        {
            return Math.Abs(Dot(a, b));
        }

        public PBRVector3 Min(PBRVector3 a, PBRVector3 b)
        {
            return new PBRVector3((float)Math.Min(a.X, b.X), (float)Math.Min(a.Y, b.Y),(float)Math.Min(a.Z, b.Z));
        }

        public PBRVector3 Max(PBRVector3 a, PBRVector3 b)
        {
            return new PBRVector3((float)Math.Max(a.X, b.X), (float)Math.Max(a.Y, b.Y),(float)Math.Max(a.Z, b.Z));
        }

        public void Normalize()
        {
            float length = Length();
            _x /= length;
            _y /= length;
            _z /= length;
        }

        public PBRVector3 Normalized(PBRVector3 a)
        {
            float length = Length();
            return a / length;
        }
        #endregion
    }
}

